/**
 * Class that provides methods to print and read from console or files.
 * 
 * @author David Alvarez Lopez
 * @email sly.dekar@gmail.com
 */

package com.dekaru.util;

import java.io.*;

public class PrintReader {

	private boolean fileInEnabled;
	private boolean fileOutEnabled;
	
	private String fileInName;
	private String fileOutName;
	
	private BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
    private PrintWriter stdOut = new PrintWriter(System.out,true);
    
    private BufferedReader fileIn;
	private PrintWriter fileOut;
	
    // ==================
    // CLASS CONSTRUCTORS 
    // ==================
	
	public PrintReader() {
		
		fileInEnabled = false;
		fileOutEnabled = false;
		stdOut.println("    [pr] Input file disabled.");
		stdOut.println("    [pr] Output file disabled.");
	}
	
	public PrintReader(String inputFileName, String outputFileName) {
		try {
			
			fileIn = new BufferedReader(new FileReader(inputFileName));
			fileInEnabled = true;
			fileInName = inputFileName;
			stdOut.println("    [pr] Input file enabled. Reading from file: " + inputFileName);
		} catch(Exception e) { 
			
			fileOutEnabled = false;
			stdOut.println("    [pr] Input file disabled. " + e.toString());
		}
		try {
			
			fileOut = new java.io.PrintWriter(new FileWriter(outputFileName));
			fileOutEnabled = true;
			fileOutName = outputFileName;
			stdOut.println("    [pr] Output file enabled. Writing to file: " + outputFileName);
		} catch(Exception e) { 
			
			fileOutEnabled = false;
			stdOut.println("    [pr] Output file disabled. " + e.toString());
		}
	}
	
    // ===================
    // GETTERS, SETTERS... 
    // ===================
	
	/**
	 * A method that returns fileIn.
	 * 
	 * @return the fileIn
	 */
	public BufferedReader getFileIn() {
		return fileIn;
	}
	/**
	 * A method that returns fileOut.
	 * 
	 * @return the fileOut
	 */
	public java.io.PrintWriter getFileOut() {
		return fileOut;
	}
	/**
	 * A method that returns fileInEnabled.
	 * 
	 * @return the fileInEnabled
	 */
	public boolean isFileInEnabled() {
		return fileInEnabled;
	}
	/**
	 * A method that returns fileOutEnabled.
	 * 
	 * @return the fileOutEnabled
	 */
	public boolean isFileOutEnabled() {
		return fileOutEnabled;
	}
	/**
	 * A method that sets the fileIn of the invoking object by the parameter given.
	 * 
	 * @param fileIn the fileIn to set
	 */
	public void setFileIn(String inputFileName ) {
		try {
			fileIn = new BufferedReader(new FileReader(inputFileName));
			fileInEnabled = true;
			fileInName = inputFileName;
			stdOut.println("    [pr] Input file enabled. Reading from file: " + inputFileName);
		} catch(Exception e) { 
			fileOutEnabled = false;
			stdOut.println("    [pr] Input file disabled. " + e.toString());
		}
	}
	/**
	 * A method that sets the fileOut of the invoking object by the parameter given.
	 * 
	 * @param fileOut the fileOut to set
	 */
	public void setFileOut(String outputFileName) {
		try {
			fileOut = new PrintWriter(new FileWriter(outputFileName));
			fileOutEnabled = true;
			fileOutName = outputFileName;
			stdOut.println("    [pr] Output file enabled. Writing to file: " + outputFileName);
		} catch(Exception e) {
			fileOutEnabled = false;
			stdOut.println("    [pr] Output file disabled. " + e.toString());
		}
	}
	/**
	 * A method that sets the fileInEnabled of the invoking object by the parameter given.
	 * 
	 * @param fileInEnabled the fileInEnabled to set
	 */
	public void setFileInEnabled(boolean fileInEnabled) {
		if (this.getFileIn() != null)
			this.fileInEnabled = fileInEnabled;
	}
	/**
	 * A method that sets the fileOutEnabled of the invoking object by the parameter given.
	 * 
	 * @param fileOutEnabled the fileOutEnabled to set
	 */
	public void setFileOutEnabled(boolean fileOutEnabled) {
		if (this.getFileOut() != null)
			this.fileOutEnabled = fileOutEnabled;
	}
	/**
	 * A method that returns fileInName.
	 * 
	 * @return the fileInName
	 */
	public String getFileInName() {
		return fileInName;
	}
	/**
	 * A method that returns fileOutName.
	 * 
	 * @return the fileOutName
	 */
	public String getFileOutName() {
		return fileOutName;
	}
	


	// ========================
    // IMPLEMENTATION OF READER 
    // ========================

	public void mark(int readAheadLimit) throws IOException {
		if (fileInEnabled) fileIn.mark(readAheadLimit);
		stdIn.mark(readAheadLimit);
	}
	public void markf(int readAheadLimit) throws IOException {
		if (fileInEnabled) fileIn.mark(readAheadLimit);
	}
	public void marks(int readAheadLimit) throws IOException {
		stdIn.mark(readAheadLimit);
	}
	
	public boolean markSupported() {
		if (fileInEnabled && stdIn.markSupported()) return true;
		else return false;
	}
	public boolean markSupportedf() {
		return fileIn.markSupported();
	}
	public boolean markSupporteds() {
		return stdIn.markSupported();
	}
	
    public int readf(char[] cbuf, int off, int len) throws IOException {
    	if (fileInEnabled) return fileIn.read(cbuf, off, len);
    	else return -1;
    }
    public int reads(char[] cbuf, int off, int len) throws IOException {
    	return stdIn.read(cbuf, off, len);
    }
    
    public String readLinef() throws IOException {
    	if (fileInEnabled) return fileIn.readLine();
    	else return "";
    }
    public String readLines() throws IOException {
    	return stdIn.readLine();
    }
    
    public boolean ready() throws IOException {
    	if (fileInEnabled) return fileIn.ready();
    	else return false;
    }
    public boolean readys() throws IOException {
    	return stdIn.ready();
    }
    
    public void reset() throws IOException {
    	if (fileInEnabled) { fileIn.reset(); stdIn.reset(); }
    }
    public void resetf() throws IOException {
    	if (fileInEnabled) fileIn.reset();
    }
    public void resets() throws IOException {
    	stdIn.reset();
    }
    
    public long skipf(long n) throws IOException {
    	if (fileInEnabled) return fileIn.skip(n);
    	else return -1;
    }
    public long skips(long n) throws IOException {
    	return stdIn.skip(n);
    }
    
    public int readf() throws IOException { 	
		if (fileInEnabled) return fileIn.read();
		else return -1;
	}
    public int reads() throws IOException { 	
		return stdIn.read();
	}
	
	// =========================
    // IMPLEMENTATION OF PRINTER
    // =========================
	
	public void println(String message) {
		if (fileOutEnabled) fileOut.println(message);
		stdOut.println(message);
	}
	public void printlnf(String message) {
		if (fileOutEnabled) fileOut.println(message);
	}
	public void printlns(String message) {
		stdOut.println(message);
	}
	
	public PrintWriter appendf(char c) {
		if (fileOutEnabled) return fileOut.append(c);
		else return null;
	}
	public PrintWriter appends(char c) {
		return stdOut.append(c);
	}
	
	public PrintWriter appendf(CharSequence csq) {
		if (fileOutEnabled) return fileOut.append(csq);
		else return null;
	}
	public PrintWriter appends(CharSequence csq) {
		return stdOut.append(csq);
	}
	
	public PrintWriter appendf(CharSequence csq, int start, int end) {
		if (fileOutEnabled) return fileOut.append(csq, start, end);
		else return null;
	}
	public PrintWriter appends(CharSequence csq, int start, int end) {
		return stdOut.append(csq, start, end);
	}
	
	public void flush() {
		if (fileOutEnabled) fileOut.flush();
		stdOut.flush();
	}
	public void flushf() {
		if (fileOutEnabled) fileOut.flush();
	}
	public void flushs() {
		stdOut.flush();
	}
	
	public void print(String s) {
		if (fileOutEnabled) fileOut.print(s);
		stdOut.print(s);
	}
	public void printf(String s) {
		if (fileOutEnabled) fileOut.print(s);
	}
	public void prints(String s) {
		stdOut.print(s);
	}

	public void println() {
		if (fileOutEnabled) fileOut.println();
		stdOut.println();
	}
	public void printlnf() {
		if (fileOutEnabled) fileOut.println();
	}
	public void printlns() {
		stdOut.println();
	}
	
	public void close() throws IOException {
		if (fileInEnabled)  { fileInEnabled  = false; fileIn.close(); }
		if (fileOutEnabled) { fileOutEnabled = false; fileOut.close(); }
	}
	public void closefi() throws IOException {
		if (fileInEnabled)  { fileInEnabled  = false; fileIn.close(); }
	}
	public void closefo() {
		if (fileOutEnabled) { fileOutEnabled = false; fileOut.close(); }
	}
	
	// =======================
    // OTHER USEFUL METHODS... 
    // =======================
	
	public String toString() {
		
		String s = "";
		
		if (fileInEnabled) {
			s += "    [pr] Input file enabled. Reading from file: " + fileInName; 
		} else {
			s += "    [pr] Input file disabled.";
		}
		s += ". \n";
		if (fileOutEnabled) {
			s += "    [pr] Output file enabled. Writing to file: " + fileOutName; 
		} else {
			s += "    [pr] Output file disabled.";
		}
		
		return s; 
	}
}